
#include "msc.h"
#include "udc.h"
#include "sd_mmc.h"
#include "time_mgr.h"
#include "boot.h"
#include "common_api.h"
#include "gpbr.h"

#define CBW_CMD_LIST_NUM  (sizeof(cbw_cmd_list)/sizeof(cbw_process_t))

COMPILER_ALIGNED(4) uint8_t firmware_version[2] = {0, 0};

COMPILER_ALIGNED(4) msc_cbw_t msc_cbw;
COMPILER_ALIGNED(4) msc_csw_t msc_csw;
COMPILER_ALIGNED(4) uint8_t msc_bulk_buffer[(PINGPONG_BUFFER_SIZE * 2)];
COMPILER_ALIGNED(4) uint8_t request_sense_data[REQUEST_SENSE_DATA_LEN + 2];
COMPILER_ALIGNED(4) uint8_t inquiry_data[INQUIRY_DATA_LEN] =
{
    0x00, 0x80, 0x04, 0x02, 0x1f, 0x00, 0x00, 0x00, 
     'm',  'o',  'p',  'h',  'i',  'e',  ' ',  ' ',
     'S',  'p',  'a',  'c',  'e',  'P',  'a',  'c',  
     'k',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',
     '1',  '.',  '0',  '0'
};
COMPILER_ALIGNED(4) uint8_t mode_sense6_data[8] =
{
    0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
COMPILER_ALIGNED(4) uint8_t mode_sense10_data[8] = 
{
    0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
COMPILER_ALIGNED(4) uint8_t format_capacity_data[FORMAT_CAPACITY_LEN] = 
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
COMPILER_ALIGNED(4) uint8_t capacity_data[CAPACITY_LEN] =
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

scsi_sense_t sense_data[4];

uint8_t   SCSI_sense_head = 0;
uint8_t   SCSI_sense_tail = 0;
uint32_t  bot_trans_len;
uint8_t   *bot_buff_ptr = NULL;
uint32_t        blk_size;
uint32_t        blk_nbr;
uint32_t        blk_addr;
uint32_t        blk_len;
ping_pong_t     ping_pong;
bool      b_specific_io;
bool      b_media_removable = false;

bool      protect_cmd_status = false;

uint8_t new_code_len = 0;
uint8_t new_code_idx = 0;

static bool msc_test_unit_ready(void);
static bool msc_request_sense(void);
static bool msc_inquiry(void);
static bool msc_start_stop_unit(void);
static bool msc_allow_medium_removal(void);
static bool msc_mode_sense6(void);
static bool msc_mode_sense10(void);
static bool msc_read_format_capacity(void);
static bool msc_read_capacity(void);
static bool msc_read(void);
static bool msc_write(void);
static bool msc_verify(void);

static bool custom_get_space_idx(void);
static bool custom_get_battery_power(void);
static bool custom_update(void);
static bool custom_update_complete(void);
static bool custom_jump(void);
static bool custom_get_contact_info(void);
static bool custom_set_contact_info(void);
static bool custom_get_dev_status(void);
static bool custom_modify_pwd(void);
static bool custom_modify_email(void);
static bool custom_close_protect(void);
static bool custom_verify_pwd(void);
static bool custom_alt_pc_mode(void);
static bool custom_get_pwd_email(void);

static bool custom_get_protect_cmd_status(void);

static bool private_get_version(void);
static bool private_force_boot(void);
static bool private_get_crc(void);
static bool private_erase_protect(void);
static bool private_get_device_id(void);
//static bool private_get_code(void);

cbw_process_t cbw_cmd_list[] =
{
    {MSC_TEST_UNIT_READY,       msc_test_unit_ready},
    {MSC_REQUEST_SENSE,         msc_request_sense},
    {MSC_INQUIRY,               msc_inquiry},
    {MSC_START_STOP_UNIT,       msc_start_stop_unit},
    {MSC_ALLOW_MEDIUM_REMOVAL,  msc_allow_medium_removal},
    {MSC_MODE_SENSE6,           msc_mode_sense6},
    {MSC_MODE_SENSE10,          msc_mode_sense10},
    {MSC_READ_FORMAT_CAPACITY,  msc_read_format_capacity},
    {MSC_READ_CAPACITY,         msc_read_capacity}, 
    {MSC_READ,                  msc_read},
    {MSC_WRITE,                 msc_write},
    {MSC_VERIFY,                msc_verify},
    
    {CUSTOM_GET_SPACE_IDX,          custom_get_space_idx},
    {CUSTOM_GET_BATTERY_POWER,      custom_get_battery_power},
    {CUSTOM_UPDATE,                 custom_update},
    {CUSTOM_UPDATE_COMPLETE,        custom_update_complete},
    {CUSTOM_JUMP,                   custom_jump},
    {CUSTOM_GET_CONTACT_INFO,       custom_get_contact_info},
    {CUSTOM_SET_CONTACT_INFO,       custom_set_contact_info},
    {CUSTOM_GET_PROTECT_CMD_STATUS, custom_get_protect_cmd_status},
    {CUSTOM_GET_DEV_STATUS,         custom_get_dev_status},
    {CUSTOM_MODIFY_PWD,             custom_modify_pwd},
    {CUSTOM_MODIFY_EMAIL,           custom_modify_email},
    {CUSTOM_CLOSE_PROTECT,          custom_close_protect},
    {CUSTOM_VERIFY_PWD,             custom_verify_pwd},
    {CUSTOM_ALT_PC_MODE,            custom_alt_pc_mode},
    {CUSTOM_GET_PWD_EMAIL,          custom_get_pwd_email},
  
    {PRIVATE_GET_VERSION,           private_get_version},
    {PRIVATE_FORCE_BOOT,            private_force_boot},
    {PRIVATE_GET_CRC,               private_get_crc},
    {PRIVATE_ERASE_ALL_PROTECT,     private_erase_protect},
    {PRIVATE_GET_DEVICE_ID,         private_get_device_id},
    //{PRIVATE_GET_CODE,              private_get_code}
};

bool msc_process(bool b_pc)
{
    //irqflags_t g_irqflag;
    uint8_t bot_status;    
  
    if((g_msc_start == 1) || (g_jpm_native_start == 1))
    {
        //g_irqflag = cpu_irq_save();
        //udd_disable_out_received_interrupt((IAP2_EP_OUT&0x0f));
        //udd_disable_endpoint_interrupt((IAP2_EP_OUT&0x0f));
        bot_status = bot_get_cbw(b_pc);
        if(bot_status == BOT_CBW_RECEIVED)
        {
            if(g_jpm_native_start == 1)
            {
                reset_sleep_timer();
            }           
            
            if(!bot_cmd_process())
            {
                return false;
            }
        }
        else if(bot_status == BOT_CBW_ERROR)
        {
            return false;
        }
        //cpu_irq_restore(g_irqflag);
        //udd_enable_endpoint_interrupt((IAP2_EP_OUT&0x0f));
        //udd_enable_out_received_interrupt((IAP2_EP_OUT&0x0f));
    }
    
    return true;
}

uint8_t bot_get_cbw(bool b_pc)
{
    uint8_t *cbw_ptr = (uint8_t*)(&msc_cbw);
    uint8_t ep_num = (MSC_EP_OUT & 0x0f);
    uint16_t rev_cnt;

    if(Is_udd_out_received(ep_num))
    {
        rev_cnt = udd_byte_count(ep_num);
        if(((rev_cnt != CBW_LEN) && (b_pc == true)) || 
           ((rev_cnt != SECTOR_SIZE) && (b_pc == false)))
        {
            udd_enable_stall_handshake(ep_num);
            udd_ack_out_received(ep_num);
            return BOT_CBW_ERROR;
        }
        
        else
        {
            if(b_pc)
            {
                udd_ep_receive_dma(ep_num, cbw_ptr, CBW_LEN, msc_bulk_size);
            }
            else
            {
                udd_ep_receive_dma(ep_num, cbw_ptr, SECTOR_SIZE, msc_bulk_size);
            }         
            //valid cbw
            if(msc_cbw.dCBWSignature != CBW_SIGNATURE)
            {
                udd_enable_stall_handshake(ep_num);
                udd_ack_out_received(ep_num);
                return BOT_CBW_ERROR;
            }
            else
            {
                msc_csw.dCSWTag = msc_cbw.dCBWTag;
            }
            
            if(!b_pc)
            {
                if(msc_cbw.dCBWsignope != CBW_SIGNATURE_OPE)
                {
                    udd_enable_stall_handshake(ep_num);
                    udd_ack_out_received(ep_num);
                    return BOT_CBW_ERROR;
                }
            }
        }     
        //udd_ack_out_received(ep_num);     
        return BOT_CBW_RECEIVED;
    }

    return BOT_NO_CMD;
}

bool bot_cmd_process(void)
{
    static bool b_pc_contact = false;
    uint8_t i = 0;
    bool b_ret = true;
    b_specific_io = false;
  
    for(i = 0; i < CBW_CMD_LIST_NUM; i++)
    {
        if(cbw_cmd_list[i].cmd == msc_cbw.CDB[0])
        {
            if((msc_cbw.CDB[0] == MSC_READ_FORMAT_CAPACITY) || 
               (msc_cbw.CDB[0] == MSC_READ_CAPACITY) ||
               (msc_cbw.CDB[0] == MSC_READ) ||
               (msc_cbw.CDB[0] == MSC_WRITE) ||
               (msc_cbw.CDB[0] == PRIVATE_ERASE_ALL_PROTECT) ||
               (msc_cbw.CDB[0] == CUSTOM_UPDATE) ||
               (msc_cbw.CDB[0] == CUSTOM_GET_SPACE_IDX) ||
               (msc_cbw.CDB[0] == CUSTOM_GET_DEV_STATUS) ||
               (msc_cbw.CDB[0] == CUSTOM_MODIFY_PWD) ||
               (msc_cbw.CDB[0] == CUSTOM_MODIFY_EMAIL) ||
               (msc_cbw.CDB[0] == CUSTOM_CLOSE_PROTECT) ||
               (msc_cbw.CDB[0] == CUSTOM_VERIFY_PWD) ||
               (msc_cbw.CDB[0] == CUSTOM_GET_PWD_EMAIL))
            {
                if(sysclk_run_fastest == false)
                {
                    enter_work_mode();
                }
                reset_standby_timer();
                reset_sleep_timer();
            }
            if(msc_cbw.CDB[0] == MSC_WRITE)
            {
                if(g_msc_start == 1)
                {
                    if(b_pc_contact == false)
                    {
                        set_pc_contact_flag(1);
                        b_pc_contact = true;
                    }
                }
            }
            bot_buff_ptr = NULL;
            bot_trans_len = 0;
            if(!(cbw_cmd_list[i].process_ptr()))
            {                
                return false;
            }           
            
            else
            {                
                b_ret = true;
            } 
            
            break;
        }       
    }
    if(i == CBW_CMD_LIST_NUM)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.dCSWDataResidue = 0;
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    if(b_specific_io == false)
    {
        if(msc_cbw.dCBWDataTransferLength != 0)
        {
             if((msc_cbw.bmCBWFlags & 0x80) == CBW_DIR_IN)
             {                   
                 send_bot_data_in();
             }
             else
             {
                 receive_bot_data_out();
             }
        }
        else
        {
             if(bot_trans_len > 0)
             {
                 msc_csw.dCSWDataResidue = bot_trans_len;
             }
        }
    }
    
    bot_send_csw();
    
    /*if(b_media_removable == true)
    {
        udd_disable();
        ex_status.usb_role = USB_NONE;
    }*/
    return b_ret;
}

void bot_send_csw(void)
{
    uint8_t *csw_ptr = (uint8_t*)(&msc_csw);
    uint8_t ep_num = (MSC_EP_IN & 0x0f);
    
    msc_csw.dCSWSignature = CSW_SIGNATURE;
    udd_ep_send_dma(ep_num, csw_ptr, 13, msc_bulk_size); 
}

void update_sense_code(uint8_t s_key, uint8_t ASC)
{
    sense_data[SCSI_sense_tail].s_key = s_key;
    sense_data[SCSI_sense_tail].w.ASC = ASC << 8;
    
    SCSI_sense_tail++;
    
    if(SCSI_sense_tail == 4)
    {
        SCSI_sense_tail = 0;
    }
}

void send_bot_data_in(void)
{
    uint8_t ep_num = (MSC_EP_IN & 0x0f);
    if(msc_cbw.dCBWDataTransferLength < bot_trans_len)
    {
        bot_trans_len = msc_cbw.dCBWDataTransferLength;
        msc_csw.dCSWDataResidue = bot_trans_len - msc_cbw.dCBWDataTransferLength; 
    }

    udd_ep_send_dma(ep_num, bot_buff_ptr, bot_trans_len, msc_bulk_size);        
}

void receive_bot_data_out(void)
{
    uint8_t ep_num = (MSC_EP_OUT & 0x0f);
    
    if(msc_csw.bCSWStatus == CSW_STATUS_PASS)
    {
        if(bot_trans_len > msc_cbw.dCBWDataTransferLength)
        {
            msc_csw.dCSWDataResidue = bot_trans_len - msc_cbw.dCBWDataTransferLength;
            bot_trans_len = msc_cbw.dCBWDataTransferLength;
        }
    }
    else
    {
        bot_buff_ptr = NULL;
        bot_trans_len = 0;
    }       

    if(!udd_ep_receive_dma(ep_num, bot_buff_ptr, msc_cbw.dCBWDataTransferLength, msc_bulk_size))
    {
        update_sense_code(ABORTED_COMMAND, 0x00);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
}

static bool msc_test_unit_ready(void)
{      
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    // judge storage-device is ready
    
    bot_trans_len = 0;
    if(msc_cbw.dCBWDataTransferLength != 0)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    if(ex_status.ex_power_type == P_SRC_PC)
    {
        if(b_media_removable == false)
        {
            update_sense_code(UNIT_ATTENTION, MEDIUM_HAVE_CHANGED);
            msc_csw.bCSWStatus = CSW_STATUS_FAIL;
            b_media_removable = true;
        }
    }
  
    return true;
}

static bool msc_request_sense(void)
{
    uint8_t i = 0;
  
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    for(i = 0; i < REQUEST_SENSE_DATA_LEN; i++)
    {
        request_sense_data[i] = 0x00;
    }
    
    request_sense_data[0] = 0xF0;
    request_sense_data[7] = REQUEST_SENSE_DATA_LEN - 8;
    
    if(SCSI_sense_head != SCSI_sense_tail)
    {
        request_sense_data[2] = sense_data[SCSI_sense_head].s_key;
        request_sense_data[12] = sense_data[SCSI_sense_head].w.b.ASCQ;
        request_sense_data[13] = sense_data[SCSI_sense_head].w.b.ASC;
        SCSI_sense_head++;
        
        if(SCSI_sense_head == 4)
        {
            SCSI_sense_head = 0;
        }
    }
    
    bot_trans_len = REQUEST_SENSE_DATA_LEN;
    bot_buff_ptr = (uint8_t*)(&(request_sense_data[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool msc_inquiry(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = INQUIRY_DATA_LEN;
    bot_buff_ptr = (uint8_t*)(&(inquiry_data[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    return true;
}

static bool msc_start_stop_unit(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 0;
    if(msc_cbw.dCBWDataTransferLength != 0)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool msc_allow_medium_removal(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 0;
    if(msc_cbw.dCBWDataTransferLength != 0)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    if(b_media_removable == true)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool msc_mode_sense6(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 8;
    bot_buff_ptr = (uint8_t*)(&(mode_sense6_data[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    return true;
}

static bool msc_mode_sense10(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 8;
    bot_buff_ptr = (uint8_t*)(&(mode_sense10_data[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    return true;
}

static bool msc_read_format_capacity(void)
{  
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    //get nbr blk_size
    if(sd_initialized)
    {
        blk_nbr = (sd_mmc_get_capacity(0) * 2);
    }
    else
    {
        blk_nbr = 0;
    }
    blk_size = SECTOR_SIZE;
    
    format_capacity_data[3] = 0x08;
    format_capacity_data[4] = (uint8_t)((blk_nbr -1) >> 24);
    format_capacity_data[5] = (uint8_t)((blk_nbr -1) >> 16);
    format_capacity_data[6] = (uint8_t)((blk_nbr -1) >> 8);
    format_capacity_data[7] = (uint8_t)(blk_nbr -1);
    
    format_capacity_data[8] = 0x02;
    format_capacity_data[9] = (uint8_t)(blk_size >> 16);
    format_capacity_data[10] = (uint8_t)(blk_size >> 8);
    format_capacity_data[11] = (uint8_t)(blk_size);
    
    bot_trans_len = FORMAT_CAPACITY_LEN;
    bot_buff_ptr = (uint8_t *)(&(format_capacity_data[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool msc_read_capacity(void)
{       
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    //get nbr/blk_size
    if(sd_initialized)
    {
        blk_nbr = (sd_mmc_get_capacity(0) * 2);
    }
    else
    {
        blk_nbr = 0;
    }
    blk_size = SECTOR_SIZE;
    
    capacity_data[0] = (uint8_t)((blk_nbr - 1) >> 24);
    capacity_data[1] = (uint8_t)((blk_nbr - 1) >> 16);
    capacity_data[2] = (uint8_t)((blk_nbr - 1) >> 8);
    capacity_data[3] = (uint8_t)(blk_nbr - 1);
    
    capacity_data[4] = (uint8_t)(blk_size >> 24);
    capacity_data[5] = (uint8_t)(blk_size >> 16);
    capacity_data[6] = (uint8_t)(blk_size >> 8);
    capacity_data[7] = (uint8_t)(blk_size);
    
    bot_trans_len = CAPACITY_LEN;
    bot_buff_ptr = (uint8_t *)(&(capacity_data[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}


static bool msc_read(void)
{
    //sd_mmc_err_t sd_mmc_err;
    uint8_t ep_num = (MSC_EP_IN & 0x0f);
    uint32_t trans_len;
    uint32_t read_blk_num;
  
    bool b_first_trans = true;
    bool b_last_trans = false;
    uint32_t next_trans_len;
    uint32_t next_read_blk_num;
    
    ping_pong.b_ping_flag = true;   
  
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    blk_addr = (msc_cbw.CDB[2] << 24) | (msc_cbw.CDB[3] << 16) | (msc_cbw.CDB[4] << 8) | (msc_cbw.CDB[5]);
    blk_len = (msc_cbw.CDB[7] << 8) | (msc_cbw.CDB[8]);
    
    if(blk_addr + blk_len > blk_nbr)
    {
        update_sense_code(ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;      
        return true;
    }   
    
    blk_addr += SD_BLK_OFFSET_ADDR;
    
    //process for usb and SD-CARD pingpong buffer convert
    bot_trans_len = blk_len * blk_size;
    bot_buff_ptr = &(msc_bulk_buffer[0]);
    
    if(bot_trans_len != msc_cbw.dCBWDataTransferLength)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_FIELD_IN_PARAMETER_LIST);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL; 
        return true;
    }
    
    /*do
    {
        if(sd_initialized == false)
        {
            return false;
        }
        sd_mmc_err = sd_mmc_init_read_blocks(0, blk_addr, blk_len);
        if(sd_mmc_err != SD_MMC_OK)
        {
            sd_mmc_init();
        }
    }while(sd_mmc_err != SD_MMC_OK);*/
    if(sd_initialized)
    {
        if(sd_mmc_init_read_blocks(0, blk_addr, blk_len) != SD_MMC_OK)
        {
            return false;
        }
    }
    
    while(bot_trans_len > 0)
    {   
        charge_led_proc();
        if(bot_trans_len <= PINGPONG_BUFFER_SIZE)
        {
           trans_len = bot_trans_len;
           b_last_trans = true;
           next_trans_len = 0;
        }
        else
        {
           trans_len = PINGPONG_BUFFER_SIZE;
           next_trans_len = bot_trans_len - trans_len;
           if(next_trans_len > PINGPONG_BUFFER_SIZE)
           {
              next_trans_len = PINGPONG_BUFFER_SIZE;
           }          
        }
        read_blk_num = trans_len / blk_size;
        next_read_blk_num = next_trans_len / blk_size;
        if(b_first_trans)
        {
            //start read to ping buffer from sd-card
            if(sd_initialized)
            {
                if(sd_mmc_start_read_blocks(ping_pong.p_ping_buf_ptr, read_blk_num) != SD_MMC_OK)
                {
                    return false;
                }
                //waite for sd-card free
                if(sd_mmc_wait_end_of_read_blocks() != SD_MMC_OK)
                {
                    return false;
                }
            }
            
            //ping_pong.b_ping_flag = false; 
            b_first_trans = false;
            continue; 
            
        }
        else
        {
            if(ping_pong.b_ping_flag)
            {
                if(!b_last_trans)
                {
                    //start read to pong buffer from sd-card
                    if(sd_initialized)
                    {
                        if(sd_mmc_start_read_blocks(ping_pong.p_pong_buf_ptr, next_read_blk_num) != SD_MMC_OK)
                        {
                            return false;
                        }
                    }
                }
                //config dma src addr to ping buffer and start dma
                udd_ep_send_dma_direct(ep_num, ping_pong.p_ping_buf_ptr, trans_len);
            }
            else
            {
                if(!b_last_trans)
                {
                    //start read to ping buffer from sd-card
                    if(sd_initialized)
                    {
                        if(sd_mmc_start_read_blocks(ping_pong.p_ping_buf_ptr, next_read_blk_num) != SD_MMC_OK)
                        {
                            return false;
                        }
                    }
                }
                //config dma src addr to pong buffer and start dma
                udd_ep_send_dma_direct(ep_num, ping_pong.p_pong_buf_ptr, trans_len);
            }
            if(!b_last_trans)
            {
                if(sd_initialized)
                {
                    if(sd_mmc_wait_end_of_read_blocks() != SD_MMC_OK)
                    {
                        return false;
                    }
                }
            } 
            ping_pong.b_ping_flag = !(ping_pong.b_ping_flag);          
            wait_for_usb_dma(ep_num, true);
            
            bot_trans_len -= trans_len;
        }                                                
    } 

    b_specific_io = true;
    
    return true;
}

static bool msc_write(void)
{
    //sd_mmc_err_t sd_mmc_err;
    uint8_t ep_num = (MSC_EP_OUT & 0x0f);
    uint32_t trans_len;
    uint32_t write_blk_num; 
    bool b_first_trans = true;
    bool b_last_trans = false;
    uint32_t next_trans_len;
    
    ping_pong.b_ping_flag = true;  
    
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_OUT)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    blk_addr = (msc_cbw.CDB[2] << 24) | (msc_cbw.CDB[3] << 16) | (msc_cbw.CDB[4] << 8) | (msc_cbw.CDB[5]);
    blk_len = (msc_cbw.CDB[7] << 8) | (msc_cbw.CDB[8]);
    
    if(blk_addr + blk_len > blk_nbr)
    {
        update_sense_code(ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;      
        return true;
    }    
    
    blk_addr += SD_BLK_OFFSET_ADDR;
    
    //process for usb and SD-CARD pingpong buffer convert
    bot_trans_len = blk_len * blk_size;
    bot_buff_ptr = &(msc_bulk_buffer[0]);
    
    if(bot_trans_len != msc_cbw.dCBWDataTransferLength)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_FIELD_IN_PARAMETER_LIST);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL; 
        return true;
    }
    
    /*do
    {
        if(sd_initialized == false)
        {
            return false;
        }
        sd_mmc_err = sd_mmc_init_write_blocks(0, blk_addr, blk_len);
        if(sd_mmc_err != SD_MMC_OK)
        {
            sd_mmc_init();
        }
    }while(sd_mmc_err != SD_MMC_OK);*/
    
    if(sd_initialized)
    {
        if(sd_mmc_init_write_blocks(0, blk_addr, blk_len) != SD_MMC_OK)
        {
            return false;
        }
    }
    
    while(bot_trans_len > 0)
    {
         charge_led_proc();
         if(bot_trans_len <= PINGPONG_BUFFER_SIZE)
         {
            trans_len = bot_trans_len;
            b_last_trans = true;
            next_trans_len = 0;
         }
         else
         {
            trans_len = PINGPONG_BUFFER_SIZE;
            next_trans_len = bot_trans_len - trans_len;
            if(next_trans_len > PINGPONG_BUFFER_SIZE)
            {
                next_trans_len = PINGPONG_BUFFER_SIZE;
            }
         }
         write_blk_num = trans_len / blk_size;
            
         if(b_first_trans)
         {
            //config dma dst addr to ping buffer and start dma
            udd_ep_receive_dma_direct(ep_num, ping_pong.p_ping_buf_ptr, trans_len);
            
            //wait dma stop
            wait_for_usb_dma(ep_num, false);               
         
            b_first_trans = false;
            continue;
         }
         else
         {
            if(ping_pong.b_ping_flag)
            {
                //start write ping buffer to sd card
                if(sd_initialized)
                {
                    if(sd_mmc_start_write_blocks(ping_pong.p_ping_buf_ptr, write_blk_num) != SD_MMC_OK)
                    {
                        return false;
                    }
                }
                
                if(!b_last_trans)                  
                {
                    //config dma dst addr to pong buffer and start dma
                    udd_ep_receive_dma_direct(ep_num, ping_pong.p_pong_buf_ptr, next_trans_len);
                    wait_for_usb_dma(ep_num, false); 
                }                
            }
            else
            {
                //start write pong buffer to sd card
                if(sd_initialized)
                {
                    if(sd_mmc_start_write_blocks(ping_pong.p_pong_buf_ptr, write_blk_num) != SD_MMC_OK)
                    {
                        return false;
                    }
                }
                
                if(!b_last_trans)
                {
                    //config dma dst addr to ping buffer and start dma
                    udd_ep_receive_dma_direct(ep_num, ping_pong.p_ping_buf_ptr, next_trans_len);
                    wait_for_usb_dma(ep_num, false); 
                }                
            }
            
            if(sd_initialized)
            {
                if(SD_MMC_OK != sd_mmc_wait_end_of_write_blocks())
                {
                    return false;
                }
            }  
            
            ping_pong.b_ping_flag = !(ping_pong.b_ping_flag);
         }
                    

         bot_trans_len -= trans_len;        
    }
            
    b_specific_io = true;
    return true;
}

static bool msc_verify(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    if((msc_cbw.CDB[1] & 0x02) == 0x02)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    //check address range
    if(blk_addr + blk_len > blk_nbr)
    {
        update_sense_code(ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;      
        return true;
    }
    
    bot_trans_len = 0;
    if(msc_cbw.dCBWDataTransferLength != 0)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool custom_get_space_idx(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    //get space index
    new_code_idx = get_code_idx();
    msc_bulk_buffer[0] = new_code_idx;
    
    bot_trans_len = 1;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool custom_get_battery_power(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    msc_bulk_buffer[0] = ex_status.led_status;
    
    bot_trans_len = 1;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool custom_get_contact_info(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    if(sd_initialized)
    {
        msc_bulk_buffer[0] = get_pc_contact_flag(); 
        get_iphone_id(msc_bulk_buffer + 1);
    }
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;    
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool custom_update(void)
{
    uint8_t code_idx;
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }

    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    udd_ep_receive_dma((MSC_EP_OUT & 0x0f), bot_buff_ptr, bot_trans_len, msc_bulk_size);
    
    //write to flash
    code_idx = msc_cbw.CDB[1];

    if(!write_new_code(code_idx, new_code_idx, bot_buff_ptr))
    {
        msc_csw.bCSWStatus = CSW_STATUS_PE;
    }
    else
    {
        if(code_idx + 1 > new_code_len)
        {
            new_code_len = code_idx + 1;
        }        
    }
    
    b_specific_io = true;
    return true;
}

static bool custom_set_contact_info(void)
{
    uint8_t pc_contact_flag;
    uint8_t iphone_id_len = 0;
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    udd_ep_receive_dma((MSC_EP_OUT & 0x0f), bot_buff_ptr, bot_trans_len, msc_bulk_size);
    
    iphone_id_len = msc_cbw.CDB[1];
    pc_contact_flag = msc_bulk_buffer[0];

    if(sd_initialized)
    {
        set_pc_contact_flag(pc_contact_flag);
    }
    
    if(iphone_id_len > 0)
    {
        if(sd_initialized)
        {
            set_iphone_id(msc_bulk_buffer + 1, iphone_id_len);
        }
    }
      
    b_specific_io = true;
    return true;
}

static bool custom_update_complete(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    if((b_need_to_verify == true) && (b_verified == false))
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        return true;
    }
    
    bot_trans_len = 0;
    if(msc_cbw.dCBWDataTransferLength != 0)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    } 
    
    if(!finish_write_code(new_code_len, new_code_idx))
    {
        msc_csw.bCSWStatus = CSW_STATUS_PE;
    }
    
    return true;
}

static bool custom_jump(void)
{
    return false;
}

static bool private_get_crc(void)
{
    uint32_t crc_result;
  
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 4;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    crc_result = get_code_crc(new_code_len, new_code_idx);
    
    *((uint32_t*)(&(msc_bulk_buffer[0]))) = crc_result;
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool private_get_version(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 2;
    bot_buff_ptr = (uint8_t*)(&(firmware_version[0]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool private_get_device_id(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 12;
    bot_buff_ptr = (uint8_t*)(&(g_modify_code[4]));
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool private_force_boot(void)
{
    //uint16_t model_number_flag = 0;
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
      
    bot_trans_len = 0;
    if(msc_cbw.dCBWDataTransferLength != 0)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    } 
    
    set_part_number(msc_cbw.CDB[1], msc_cbw.CDB[2]);
    erase_valid();
  
    return false;
}

static bool custom_close_protect(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 0;
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }    
    
    if((b_verified == true) && (b_need_to_verify == true))
    {
        clear_pwd_need();
        protect_cmd_status = true;
    }
    else
    {
        protect_cmd_status = false;
    }
    
    return true;
}

static bool custom_verify_pwd(void)
{
    uint32_t tmp_len;
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    reset_applaunch_timer();
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    udd_ep_receive_dma((MSC_EP_OUT & 0x0f), bot_buff_ptr, bot_trans_len, msc_bulk_size);
    //udd_ep_receive_one_pkt((MSC_EP_OUT & 0x0f), bot_buff_ptr, &tmp_len);
    //while(!Is_udd_out_received(MSC_EP_OUT & 0x0f)); 
    //udd_ack_out_received(MSC_EP_OUT & 0x0f);
    
    if(b_need_to_verify == false)
    {
        protect_cmd_status = false;
        b_verified = false;
    }
    else
    {
        b_verified = verify_pwd(msc_bulk_buffer);
        protect_cmd_status = b_verified;           
    }   
  
    b_specific_io = true;
    return true;
}

static bool custom_alt_pc_mode(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if(ex_status.ex_power_type != P_SRC_PC_PRE)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    if((b_need_to_verify == true) && (b_verified == true))
    {
        restor_pc_verified_flag();
    }
    else
    {
        clear_pc_verified_flag();
    }
    
    restore_pc_flag();
    restore_battery_power(true, true);
    
    return false;
}

static bool custom_modify_email(void)
{   
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }    
    
    udd_ep_receive_dma((MSC_EP_OUT & 0x0f), bot_buff_ptr, bot_trans_len, msc_bulk_size);   
    
    if((b_verified == true) && (b_need_to_verify == true))
    {
        modify_email_addr(msc_bulk_buffer);
        protect_cmd_status = true;
    }
    else if(b_need_to_verify == false)
    {
        modify_email_addr(msc_bulk_buffer);
        protect_cmd_status = true;
    }
    else
    {
        protect_cmd_status = false;
    }
  
    b_specific_io = true;
    return true;
}

static bool custom_modify_pwd(void)
{
    uint8_t *old_pwd;
    uint8_t *new_pwd;
    
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    reset_applaunch_timer();
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    udd_ep_receive_dma((MSC_EP_OUT & 0x0f), bot_buff_ptr, bot_trans_len, msc_bulk_size);
    
    old_pwd = &(msc_bulk_buffer[0]);
    new_pwd = &(msc_bulk_buffer[16]);
    
    
    if(b_need_to_verify == true)
    {
        if(verify_pwd(old_pwd) == true)
        {
            protect_cmd_status = true;
            b_verified = true;
        }
        else
        {
            protect_cmd_status = false;
        }
    }
    else
    {
        protect_cmd_status = true;
        b_verified = true;
        if(Is_email_set())
        {
            b_need_to_verify = true;
        }
    }
    
    if(protect_cmd_status == false)
    {
        b_specific_io = true;
        return true;
    }
    
    store_pwd(new_pwd, false);    
  
    b_specific_io = true;
    return true;
}

static bool private_erase_protect(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = msc_cbw.dCBWDataTransferLength;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    udd_ep_receive_dma((MSC_EP_OUT & 0x0f), bot_buff_ptr, bot_trans_len, msc_bulk_size);
    
    if(common_mem_cmp(msc_bulk_buffer, "santiago_force_erase_protect", 28) == false)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    erase_all_protection();
  
    b_specific_io = true;
    return false;
}

static bool custom_get_pwd_email(void)
{
    uint8_t ran_seed[4];
  
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    stop_applaunch_timer();
    
    bot_trans_len = 272;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    common_mem_cpy(&(msc_cbw.CDB[1]), ran_seed, 4);
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    if(b_need_to_verify == false)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
    
    get_pwd_email(msc_bulk_buffer, ran_seed);
    if(Is_email_set())
    {
        b_need_to_verify = true;
    }
    b_verified = false;
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

static bool custom_get_protect_cmd_status(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 1;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if(protect_cmd_status == true)
    {
        msc_bulk_buffer[0] = 1;
    }
    else
    {
        msc_bulk_buffer[0] = 0;
    }
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    protect_cmd_status = false;
    
    return true;
}

static bool custom_get_dev_status(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 512;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    if(!sd_initialized)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
        
        return true;
    }
 
    if(Is_email_set())
    {
        msc_bulk_buffer[3] = 0;
        get_email_addr(&(msc_bulk_buffer[5]));
    }
    else
    {
        msc_bulk_buffer[3] = 1;
        msc_bulk_buffer[5] = 0;
    }

    if(b_need_to_verify == true)
    {
        msc_bulk_buffer[0] = 1;
        msc_bulk_buffer[1] = 1;
        
        //b_need_to_verify = true;
    }
    else
    {
        msc_bulk_buffer[0] = 0;
        msc_bulk_buffer[1] = 0;
        
        //b_need_to_verify = false;
    }
    
    if(ex_status.ex_power_type == P_SRC_PC_PRE)
    {
        msc_bulk_buffer[2] = 1; 
    }
    else
    {
        msc_bulk_buffer[2] = 0;
    }
    
    if(Is_temp_pwd())
    {
        msc_bulk_buffer[4] = 1;               
    }
    else
    {
        msc_bulk_buffer[4] = 0;       
    }
    
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}

/*static bool private_get_code(void)
{
    msc_csw.dCSWDataResidue = 0;
    msc_csw.bCSWStatus = CSW_STATUS_PASS;
    
    bot_trans_len = 512;
    bot_buff_ptr = (uint8_t*)(&(msc_bulk_buffer[0]));
    
    get_code(msc_cbw.CDB[1], new_code_idx, msc_bulk_buffer);
    
    if((msc_cbw.bmCBWFlags & 0x80) != CBW_DIR_IN)
    {
        update_sense_code(ILLEGAL_REQUEST, INVALID_CDB);
        msc_csw.bCSWStatus = CSW_STATUS_FAIL;
    }
    
    return true;
}*/

uint8_t get_pc_contact_flag(void)
{
    uint8_t buf[512];
    //sd_mmc_err_t sd_mmc_err;
    
    /*do{
        sd_mmc_err = sd_mmc_init_read_blocks(0,PC_CONNECT_FLAG_BLK_ADDR,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_start_read_blocks(buf,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_wait_end_of_read_blocks();
    }while(sd_mmc_err != SD_MMC_OK);
    */
    sd_read_blk(buf, PC_CONNECT_FLAG_BLK_ADDR);
    
    return buf[0];
}

uint8_t get_iphone_id(uint8_t *id_buf)
{
    uint8_t id_len = 0;
    //uint8_t i;
    uint8_t buf[512];
    //sd_mmc_err_t sd_mmc_err;
    
   /* do{
        sd_mmc_err = sd_mmc_init_read_blocks(0,IPHONE_ID_BLK_ADDR,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_start_read_blocks(buf,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_wait_end_of_read_blocks();
    }while(sd_mmc_err != SD_MMC_OK);*/
    
    sd_read_blk(buf, IPHONE_ID_BLK_ADDR);
    
    id_len = buf[0];
    
    common_mem_cpy(buf + 1, id_buf, id_len);
    /*for(i=0;i<id_len;i++)
    {
        *id_buf = buf[i+1];
        id_buf++;
    }*/
    return id_len;
}

void set_pc_contact_flag(uint8_t flag)
{
    //sd_mmc_err_t sd_mmc_err;
    uint8_t buf[512];
    
    buf[0] = flag;
    
    /*do{
        sd_mmc_err = sd_mmc_init_write_blocks(0,PC_CONNECT_FLAG_BLK_ADDR,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_start_write_blocks(buf,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_wait_end_of_write_blocks();
    }while(sd_mmc_err != SD_MMC_OK);*/
    sd_write_blk(buf, PC_CONNECT_FLAG_BLK_ADDR);
}

void set_iphone_id(uint8_t *id_buf, uint8_t id_len)
{
    //sd_mmc_err_t sd_mmc_err;
    uint8_t buf[512];
    
    buf[0] = id_len;
    common_mem_cpy(id_buf, buf + 1, id_len);
    /*for(i=0;i<id_len;i++)
    {
        buf[i+1] = *id_buf;
        id_buf++;
    }*/
    /*
    do{
        sd_mmc_err = sd_mmc_init_write_blocks(0,IPHONE_ID_BLK_ADDR,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_start_write_blocks(buf,1);
    }while(sd_mmc_err != SD_MMC_OK);
    
    do{
        sd_mmc_err = sd_mmc_wait_end_of_write_blocks();
    }while(sd_mmc_err != SD_MMC_OK);*/
    
    sd_write_blk(buf, IPHONE_ID_BLK_ADDR);
}






